package testcircuits;

import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;

import org.junit.Before;
import org.junit.Test;

import circuits.AndOperator;
import circuits.Input;
import circuits.NotOperator;
import circuits.Operand;
import circuits.OrOperator;
import circuits.Output;
import circuits.SimpleComponent;
import circuits.XorOperator;

public class TestSimpleComponent {

	private SimpleComponent simpleComponent;
	private Input inputOn1;
	private Input inputOn2;
	private Input inputOff1;
	private Input inputOff2;
	private Output output;
	private static final String INPUT_NAME_1 = "E1";
	private static final String INPUT_NAME_2 = "E2";
	
	@Before
	public void setUp(){
		this.simpleComponent = new SimpleComponent();
		this.inputOn1 = new StubOnInput();
		this.inputOn2 = new StubOnInput();
		this.inputOff1 = new StubOffInput();
		this.inputOff2 = new StubOffInput();
		this.output = new StubOutput();
	}
	
	@Test
	public void connectTrueInputsSetAndOperatorGetTrueOutput(){
		this.simpleComponent.addInputName(INPUT_NAME_1);
		this.simpleComponent.addInputName(INPUT_NAME_2);
		this.simpleComponent.connectInput(INPUT_NAME_1, this.inputOn1);
		this.simpleComponent.connectInput(INPUT_NAME_2, this.inputOn2);
		this.simpleComponent.connectOutput(this.output);
		Operand operand1 = new Operand();
		Operand operand2 = new Operand();
		AndOperator andOperator = new AndOperator();
		andOperator.addOperand(operand1);
		andOperator.addOperand(operand2);
		this.simpleComponent.setOperand(INPUT_NAME_1, operand1);
		this.simpleComponent.setOperand(INPUT_NAME_2, operand2);
		this.simpleComponent.setOperation(andOperator);
		
		this.simpleComponent.readInputValues();
		this.simpleComponent.generateOutput();
		
		assertTrue(this.simpleComponent.readOutput());
	}
	
	@Test
	public void connectSomeFalseInputsSetAndOperatorGetFalseOutput(){
		this.simpleComponent.addInputName(INPUT_NAME_1);
		this.simpleComponent.addInputName(INPUT_NAME_2);
		this.simpleComponent.connectInput(INPUT_NAME_1, this.inputOn1);
		this.simpleComponent.connectInput(INPUT_NAME_2, this.inputOff1);
		this.simpleComponent.connectOutput(this.output);
		Operand operand1 = new Operand();
		Operand operand2 = new Operand();
		AndOperator andOperator = new AndOperator();
		andOperator.addOperand(operand1);
		andOperator.addOperand(operand2);
		this.simpleComponent.setOperand(INPUT_NAME_1, operand1);
		this.simpleComponent.setOperand(INPUT_NAME_2, operand2);
		this.simpleComponent.setOperation(andOperator);
		
		this.simpleComponent.readInputValues();
		this.simpleComponent.generateOutput();
		
		assertFalse(this.simpleComponent.readOutput());
	}
	
	@Test
	public void connectFalseInputsSetOrOperatorGetFalseOutput(){
		this.simpleComponent.addInputName(INPUT_NAME_1);
		this.simpleComponent.addInputName(INPUT_NAME_2);
		this.simpleComponent.connectInput(INPUT_NAME_1, this.inputOff1);
		this.simpleComponent.connectInput(INPUT_NAME_2, this.inputOff2);
		this.simpleComponent.connectOutput(this.output);
		Operand operand1 = new Operand();
		Operand operand2 = new Operand();
		OrOperator orOperator = new OrOperator();
		orOperator.addOperand(operand1);
		orOperator.addOperand(operand2);
		this.simpleComponent.setOperand(INPUT_NAME_1, operand1);
		this.simpleComponent.setOperand(INPUT_NAME_2, operand2);
		this.simpleComponent.setOperation(orOperator);
		
		this.simpleComponent.readInputValues();
		this.simpleComponent.generateOutput();
		
		assertFalse(this.simpleComponent.readOutput());
	}
	
	@Test
	public void connectSomeTrueInputsSetOrOperatorGetTrueOutput(){
		this.simpleComponent.addInputName(INPUT_NAME_1);
		this.simpleComponent.addInputName(INPUT_NAME_2);
		this.simpleComponent.connectInput(INPUT_NAME_1, this.inputOff1);
		this.simpleComponent.connectInput(INPUT_NAME_2, this.inputOn1);
		this.simpleComponent.connectOutput(this.output);
		Operand operand1 = new Operand();
		Operand operand2 = new Operand();
		OrOperator orOperator = new OrOperator();
		orOperator.addOperand(operand1);
		orOperator.addOperand(operand2);
		this.simpleComponent.setOperand(INPUT_NAME_1, operand1);
		this.simpleComponent.setOperand(INPUT_NAME_2, operand2);
		this.simpleComponent.setOperation(orOperator);
		
		this.simpleComponent.readInputValues();
		this.simpleComponent.generateOutput();
		
		assertTrue(this.simpleComponent.readOutput());
	}
	
	@Test
	public void connectFalseInputsSetXorOperatorGetFalseOutput(){
		this.simpleComponent.addInputName(INPUT_NAME_1);
		this.simpleComponent.addInputName(INPUT_NAME_2);
		this.simpleComponent.connectInput(INPUT_NAME_1, this.inputOff1);
		this.simpleComponent.connectInput(INPUT_NAME_2, this.inputOff2);
		this.simpleComponent.connectOutput(this.output);
		Operand operand1 = new Operand();
		Operand operand2 = new Operand();
		XorOperator xorOperator = new XorOperator();
		xorOperator.addOperand(operand1);
		xorOperator.addOperand(operand2);
		this.simpleComponent.setOperand(INPUT_NAME_1, operand1);
		this.simpleComponent.setOperand(INPUT_NAME_2, operand2);
		this.simpleComponent.setOperation(xorOperator);
		
		this.simpleComponent.readInputValues();
		this.simpleComponent.generateOutput();
		
		assertFalse(this.simpleComponent.readOutput());
	}
	
	@Test
	public void connectTrueInputsSetXorOperatorGetFalseOutput(){
		this.simpleComponent.addInputName(INPUT_NAME_1);
		this.simpleComponent.addInputName(INPUT_NAME_2);
		this.simpleComponent.connectInput(INPUT_NAME_1, this.inputOn1);
		this.simpleComponent.connectInput(INPUT_NAME_2, this.inputOn2);
		this.simpleComponent.connectOutput(this.output);
		Operand operand1 = new Operand();
		Operand operand2 = new Operand();
		XorOperator xorOperator = new XorOperator();
		xorOperator.addOperand(operand1);
		xorOperator.addOperand(operand2);
		this.simpleComponent.setOperand(INPUT_NAME_1, operand1);
		this.simpleComponent.setOperand(INPUT_NAME_2, operand2);
		this.simpleComponent.setOperation(xorOperator);
		
		this.simpleComponent.readInputValues();
		this.simpleComponent.generateOutput();
		
		assertFalse(this.simpleComponent.readOutput());
	}
	
	@Test
	public void connectSomeTrueInputsSetXorOperatorGetTrueOutput(){
		this.simpleComponent.addInputName(INPUT_NAME_1);
		this.simpleComponent.addInputName(INPUT_NAME_2);
		this.simpleComponent.connectInput(INPUT_NAME_1, this.inputOn1);
		this.simpleComponent.connectInput(INPUT_NAME_2, this.inputOff2);
		this.simpleComponent.connectOutput(this.output);
		Operand operand1 = new Operand();
		Operand operand2 = new Operand();
		XorOperator xorOperator = new XorOperator();
		xorOperator.addOperand(operand1);
		xorOperator.addOperand(operand2);
		this.simpleComponent.setOperand(INPUT_NAME_1, operand1);
		this.simpleComponent.setOperand(INPUT_NAME_2, operand2);
		this.simpleComponent.setOperation(xorOperator);
		
		this.simpleComponent.readInputValues();
		this.simpleComponent.generateOutput();
		
		assertTrue(this.simpleComponent.readOutput());
	}
	
	@Test
	public void connectTrueInputSetNotOperatorGetFalseOutput(){
		this.simpleComponent.addInputName(INPUT_NAME_1);
		this.simpleComponent.connectInput(INPUT_NAME_1, this.inputOn1);
		this.simpleComponent.connectOutput(this.output);
		Operand operand = new Operand();
		NotOperator notOperator = new NotOperator(operand);
		this.simpleComponent.setOperand(INPUT_NAME_1, operand);
		this.simpleComponent.setOperation(notOperator);
		
		this.simpleComponent.readInputValues();
		this.simpleComponent.generateOutput();
		
		assertFalse(this.simpleComponent.readOutput());
	}
	
	@Test
	public void connectFalseInputSetNotOperatorGetTrueOutput(){
		this.simpleComponent.addInputName(INPUT_NAME_1);
		this.simpleComponent.connectInput(INPUT_NAME_1, this.inputOff1);
		this.simpleComponent.connectOutput(this.output);
		Operand operand = new Operand();
		NotOperator notOperator = new NotOperator(operand);
		this.simpleComponent.setOperand(INPUT_NAME_1, operand);
		this.simpleComponent.setOperation(notOperator);
		
		this.simpleComponent.readInputValues();
		this.simpleComponent.generateOutput();
		
		assertTrue(this.simpleComponent.readOutput());
	}
	
}
